package com.example.anonymousinnerclass;

import java.util.concurrent.Callable;

public class OuterClass {

    private String message = "hello，world";

    private Callable<String> callable = new Callable<String>() {

        {
            System.out.println("匿名内部类Callable中的初始化代码块被执行");
        }

        static {
            System.out.println("这是一个在定义外部类成员变量时创建的匿名内部类的静态初始化块中输出的消息");
        }
        @Override
        public String call() throws Exception {
            System.out.println("在callable中直接通过message变量名访问外部类的实例变量message的值：" + message);
            System.out.println("在callable中通过OuterClass.this.message访问外部类的实例变量message的值：" + OuterClass.this.message);
            return "这是在callable的call方法中返回的值";
        }
    };

    public void doSomething(){

        int localIntVariable = 100;

        // 由于Runnable接口中没有staticString这个静态变量，
        // 所以runnable如果指定为Runnable类型，那么将无法在外部类中访问staticString
        // 为了在外部类中访问staticString，可以将引用的类型使用var关键字来指定
        // 这种做法可以实现一个效果：由于匿名内部类只会被初始化一次，因此重复调用doSomething方法访问runnable.staticString其实访问的是同一个对象，
        // 这可以模拟C语言中的局部静态变量
        var runnable = new Runnable() {

            private int anInt  = 10; // OK
            //static int anInt2 = 20; // 错误，定义static成员（变量/方法/代码块）是是不被允许的，除非这个成员是编译时常量
            static final int anInt3 = 30; // OK，定义编译时常量是允许的

            static String staticString = "这是匿名内部类Runnable中的静态变量"; // JDK16及以上版本可以定义静态变量/方法/代码块

            static {
                System.out.println("匿名内部类Runnable中的静态代码块被执行");
            } //编译错误

            // static void staticMethod(){} 编译错误

            @Override
            public void run() {
                // 定义在外部类实例方法中的匿名内部类可以直接通过"外部类.this"来访问外部类的实例
                System.out.println(OuterClass.this.message);
                System.out.println(staticString);
            }
        };
        runnable.run();

        System.out.println("在外部类访问匿名内部类中定义的静态变量：" + runnable.staticString);

    }

    public static void doOthers(){
        int anInt = 20;
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                // System.out.println(OuterClass.this.message); // 错误！当前匿名内部类不是定义在外部类的实例方法中，所以不能通过"外部类.this"来引用外部类的实例

                // 可以访问局部变量
                System.out.println(anInt);
            }
        };
        runnable.run();
    }

    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            // 可以通过"外部类.this"访问外部类的实例
            OuterClass outerClass = OuterClass.this;
            System.out.println(outerClass.message);
        }
    };

    public static void main(String[] args) throws Exception {
        OuterClass outerClass = new OuterClass();
        // 值得注意的是，我调用了两次doSomething，这虽然会创建了两次匿名内部类的实例，但是对应的匿名内部类的实例只会被加载和初始化一次，
        // 不会重复初始化（也不会因为调用两次而创建两个不同的匿名内部类）
        outerClass.doSomething();
        outerClass.doSomething();
        outerClass.runnable.run();
        OuterClass.doOthers();

        outerClass.callable.call();
    }
}
